//
//  LTGCDViewController.m
//  Total
//
//  Created by xin on 2017/6/27.
//  Copyright © 2017年 elephants. All rights reserved.
//

#import "LTGCDViewController.h"
#import "LTDownloadOperation.h"
#import <AFNetworking.h>

@interface LTGCDViewController () <LTDownloadOperationDelegate>
{
    LTDownloadOperation * downloadOperation;
    dispatch_source_t _timer;
}
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIButton *VerificationButton;

@end

@implementation LTGCDViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:self action:@selector(popCurrentViewController)];
    
    /*
     
     使用NSOperation子类的方式有3种：
     
     1> NSInvocationOperation
     
     2> NSBlockOperation
     
     3> 自定义子类继承NSOperation，实现内部相应的方法
     
     */
    
    //一、NSInvocationOperation
    NSInvocationOperation * invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(NSInvocationOperationRun:) object:@"NSInvocationOperation"];
    [invocationOperation start];
    
    //二、NSBlockOperation
    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block直行了一个操作");
    }];
    [blockOperation start];
    
    //1.以上两个都是在当前线程同步执行操作
    
    //2.并发执行多个操作 可以看出，每个操作所在线程的num值都不一样，说明是不同线程
    /*
     通过三次不同结果的比较，我们可以看到，NSBlockOperation确实实现了多线程。但是我们可以看到，它并非是将所有的block都放到放到了子线程中。通过上面的打印记录我们可以发现，它会优先将block放到主线程中执行，若主线程已有待执行的代码，就开辟新的线程，但最大并发数为4（包括主线程在内）。如果block数量大于了4，那么剩下的Block就会等待某个线程空闲下来之后被分配到该线程，且依然是优先分配到主线程。
     最大并发数为4，使用同一个线程的block一定是等待前一个block的代码全部执行结束后才执行，且同步执行
     
     关于最大并发数
     在刚才的结果中我们看到最大并发数为4，但这个值并不是一个固定值。4是我在模拟器上运行的结果，而如果我使用真机来跑的话，最大并发数始终为2。因此，具体的最大并发数和运行环境也是有关系的。我们不必纠结于这个数字

     */
    NSBlockOperation * concurrentOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"执行第1次操作，线程：%@", [NSThread currentThread]);
    }];
    
    [concurrentOperation addExecutionBlock:^{
        NSLog(@"执行第2次操作，线程：%@", [NSThread currentThread]);
    }];
    
    [concurrentOperation addExecutionBlock:^{
        NSLog(@"执行第3次操作，线程：%@", [NSThread currentThread]);
    }];
    
    [concurrentOperation addExecutionBlock:^{
        NSLog(@"执行第4次操作，线程：%@", [NSThread currentThread]);
    }];
    
    [concurrentOperation start];
    
    //三、NSOperation的其他用法
    
    //1.取消操作
    [concurrentOperation cancel];
    
    //2.在操作完成后做一些事情
    concurrentOperation.completionBlock = ^{
        NSLog(@"执行完毕");
    };
    
    
    NSInvocationOperation * op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testNSInvocationOperation1) object:nil];
    NSInvocationOperation * op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(testNSInvocationOperation2) object:nil];
    NSOperationQueue * queue = [[NSOperationQueue alloc]init];
    [op2 addDependency:op1];
    [queue addOperation:op1];
    [queue addOperation:op2];
    
    //GCD http://www.jianshu.com/p/d56064507fb8
    /*
     Serial 	串行队列将任务以先进先出(FIFO)的顺序来执行，所以串行队列经常用来做访问某些特定资源的同步处理。你可以也根据需要创建多个队列，而这些队列相对其他队列都是并发执行的。换句话说，如果你创建了4个串行队列，每一个队列在同一时间都只执行一个任务，对这四个任务来说，他们是相互独立且并发执行的。如果需要创建串行队列，一般用dispatch_queue_create这个方法来实现。
     Concurrent 	并发队列虽然是能同时执行多个任务，但这些任务仍然是按照先到先执行(FIFO)的顺序来执行的。并发队列会基于系统负载来合适地选择并发执行这些任务。在iOS5之前，并发队列一般指的就是全局队列(Global queue)，进程中存在四个全局队列：高、中(默认)、低、后台四个优先级队列，可以调用dispatch_get_global_queue函数传入优先级来访问队列。而在iOS5之后，我们也可以用dispatch_queue_create，并指定队列类型DISPATCH_QUEUE_CONCURRENT，来自己创建一个并发队列。
     Main dispatch queue 	与主线程功能相同。实际上，提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的，所以这是一个串行队列。和其它串行队列一样，这个队列中的任务一次只能执行一个。它能保证所有的任务都在主线程执行，而主线程是唯一可用于更新 UI 的线程。
     */
    
    //后台执行
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"后台执行，线程：%@", [NSThread currentThread]);
    });
    
    //主线程执行
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"主线程执行，线程：%@", [NSThread currentThread]);
    });
    
    //一次性执行
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"一次性执行，线程：%@", [NSThread currentThread]);
    });
    
    //延迟2秒执行
    double delayInSeconds = 2.0;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延迟2秒执行，线程：%@", [NSThread currentThread]);
    });
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^{
        
    });
    
    AFHTTPSessionManager * manager = [[AFHTTPSessionManager alloc] init];
    NSURL * url = [NSURL URLWithString:@"http://www.w3school.com.cn/i/movie.mp4"];
    NSURLRequest * request = [[NSURLRequest alloc] initWithURL:url];
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"downloadProgress=%f",downloadProgress.fractionCompleted);
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        NSLog(@"targetPath=%@",targetPath);
        NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
        NSLog(@"documentsDirectoryURL=%@",[documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]]);
        return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        NSLog(@"下载完成");
    }];
    [downloadTask resume];
    
    if([[url absoluteString] hasSuffix:@"/"])
    {
        NSLog(@"尾部包含/");
        
    }
    else
    {
        NSLog(@"尾部不包含/");
        url = [url URLByAppendingPathComponent:@""];
    }
    NSLog(@"url=%@",url);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

- (void)popCurrentViewController
{
    if (_timer) {
        dispatch_source_cancel(_timer);
    }
    
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)testNSInvocationOperation1
{
    NSLog(@"我是op1  我在第%@个线程",[NSThread currentThread]);
}
- (void)testNSInvocationOperation2
{
    NSLog(@"我是op2 我在第%@个线程",[NSThread currentThread]);
}

- (void)NSInvocationOperationRun:(id)sender
{
    
}

- (IBAction)downloadImageMethod:(id)sender {
    
    NSString * url = @"http://cdn.cocimg.com/assets/images/logo.png?v=201510272";
    
    downloadOperation = [[LTDownloadOperation alloc] initWithUrl:url delegate:self];
    [downloadOperation start];
}

- (IBAction)clearImageMethod:(id)sender {
    
    _imageView.image = nil;
    
}

- (void)downloadFinishWithImage:(UIImage *)image
{
    _imageView.image = image;
}

- (IBAction)verificationCodeMethod:(id)sender {
    
    //倒计时 GCD timer
    __block int timeout = 59;
    dispatch_queue_t time_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, time_queue);
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0),1.0 * NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        if(timeout <= 0)
        {
            dispatch_source_cancel(_timer);
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.VerificationButton setTitle:@"重新获取" forState:UIControlStateNormal];
                self.VerificationButton.userInteractionEnabled = YES;
                
            });
        }else
        {
            int seconds = timeout % 60;
            NSString * strTime = [NSString stringWithFormat:@"%.2d",seconds];
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.VerificationButton setTitle:[NSString stringWithFormat:@"%@%@",strTime,@"重新获取"] forState:UIControlStateNormal];
                self.VerificationButton.userInteractionEnabled = NO;
            });
            timeout--;
        }
        NSLog(@"timeout=%d",timeout);
    });
    dispatch_resume(_timer);
}

@end
